﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace Neuron
{
    public static class CustomSkelHelper
    {
        static int ExtraBoneId = IdGeneratorBase;
        public static Dictionary<string, int> ExtraNeuronBones_name_id = new Dictionary<string, int>();
        public static Dictionary<int, string> ExtraNeuronBones_id_name = new Dictionary<int, string>();

        public static int IdGeneratorBase { get { return (int)NeuronBones.NumOfBones + 1; } }
        public static bool IsExistExtraBone { get { return ExtraNeuronBones_id_name.Count > 0; } }
        public static int ExtraBoneCount { get { return ExtraNeuronBones_id_name.Count; } }

        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        public static void Init()
        {
            ExtraBoneId = IdGeneratorBase;
            ExtraNeuronBones_name_id.Clear();
            ExtraNeuronBones_id_name.Clear();
        }

        public static int AddExtraBone(string name)
        {
            int index;
            if (ExtraNeuronBones_name_id.TryGetValue(name, out index))
            {
                return index;
            }
            else
            {
                index = ExtraBoneId++;
                ExtraNeuronBones_name_id.Add(name, index);
                ExtraNeuronBones_id_name.Add(index, name);
                return index;
            }
        }

        public static string GetBoneName(int id)
        {
            string name;
            if (ExtraNeuronBones_id_name.TryGetValue(id, out name))
            {
                return name;
            }
            else
            {
                return null;
            }
        }

        public static int GetBoneIndex(string name)
        {
            int index;
            if (ExtraNeuronBones_name_id.TryGetValue(name, out index))
            {
                return index;
            }
            else
            {
                return -1;
            }
        }

        // bind transform hierachy to bones
        public static bool BindStandardBone(Transform root, Transform[] bones, string prefix, bool verbose)
        {
            NeuronHelper.Bind(root, bones, prefix, verbose);// >= (int)NeuronBones.NumOfBones;
            return true;
        }

        public static int BindExtraBone(Transform root, Transform[] bones, string prefix, bool verbose)
        {
            if (root == null)
            {
                Debug.LogError("[NeuronExtraSkeletonHelper] Root is null, bind failed.");
                return 0;
            }

            int counter = 0;
            Stack<Transform> stack = new Stack<Transform>();
            stack.Push(root);

            while (stack.Count > 0)
            {
                Transform t = stack.Pop();
                if (t.name.StartsWith(prefix))
                {
                    string bone_name = t.name.Substring(t.name.IndexOf(prefix) + prefix.Length);
                    int index = CustomSkelHelper.GetBoneIndex(bone_name);
                    if (index >= IdGeneratorBase)
                    {
                        bones[index-IdGeneratorBase] = t;
                        ++counter;
                    }
                    else if (verbose)
                    {
                        Debug.LogWarning(string.Format("[NeuronExtraSkeletonHelper] Ignore bone {0}", bone_name), t);
                    }
                }
                else if (verbose)
                {
                    Debug.LogWarning(string.Format("[NeuronExtraSkeletonHelper] Ignore transform {0}", t.name), t);
                }

                for (int i = 0; i < t.childCount; ++i)
                {
                    stack.Push(t.GetChild(i));
                }
            }

            if (verbose)
            {
                if (counter < ExtraNeuronBones_id_name.Count)
                {
                    int i = 0;
                    var iter = ExtraNeuronBones_name_id.GetEnumerator();
                    while (iter.MoveNext())
                    {
                        if (bones[i++] == null)
                        {
                            Debug.LogError(string.Format("[NeuronExtraSkeletonHelper] Bone \"{0}\" not bound", iter.Current.Key));
                        }
                    }
                }
                else
                {
                    Debug.Log(string.Format("[NeuronExtraSkeletonHelper] {0} bones bounded", counter), root);
                }
            }

            return counter;
        }
    }
}